package com.hnit.care.netty;


import com.hnit.care.config.WebSocketHandler;
import com.hnit.care.handler.HandlerData;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.CharsetUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
    @Resource
    private HandlerData handlerData;

    @Resource
    private WebSocketHandler webSocketHandler;
    /*
    * 客户端连接时，将客户端信息保存到Map中
    * */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("有客户端连接：{}",getClientIp(ctx.channel()));
        String clientIp = getClientIp(ctx.channel());
        NettyClient client = new NettyClient((SocketChannel) ctx.channel(),getClientIp(ctx.channel()));
        NettyChannelMap.add(clientIp,client);
        //向硬件传输初始化数据
        //webSocketHandler.send("有客户端连接");
    }

    /*
    * 客户端断开连接时，将客户端信息从Map中移除
    * */
    @Override
    public void channelInactive(ChannelHandlerContext ctx){
        log.info("客户端断开连接，{}",getClientIp(ctx.channel()));
        NettyChannelMap.remove((SocketChannel) ctx.channel());
    }

    /*
    * 异常处理
    * */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws Exception{
        log.info("抛出异常，包括客户端断开连接时，会抛出IO异常");
        cause.printStackTrace(); //打印异常堆栈信息
    }

    public void doServerReply(String msg) throws IOException {
        Socket socket = new Socket("",5678);
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write(msg.getBytes(CharsetUtil.UTF_8)); //转换为字节数组
        outputStream.flush();
    }

    /*
    * 收到客户端消息后，向单独客户端发送消息
    * */
    public void doReply(ChannelHandlerContext ctx,String msg){
        ctx.channel().writeAndFlush(msg);
        System.out.println("服务器返回数据：" + msg);
    }

    /*
    * 向所有客户端转发消息
    * */
    public void doAllReplay(String message){
        System.out.println("------");
        for (NettyClient value: NettyChannelMap.map.values()){
            System.out.println("服务器=>客户端:"+value.getChannel().remoteAddress().getAddress()+"=>数据:"+message);
            value.getChannel().writeAndFlush(message);
        }
        System.out.println("------");
    }

    /*
    * 获取客户端ip
    * */

    private String getClientIp(Channel channel){
        InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.remoteAddress();
        String clientIP = inetSocketAddress.getAddress().getHostAddress();
        return clientIP;
    }

    /*
    * 接收到消息后 进行处理
    * */
    @Override
    protected void messageReceived(ChannelHandlerContext ctx, String message) throws Exception {
        String[] Msg = message.split("T");

        for (String msg: Msg){
            msg = msg + "T";
            //打印数据源以及内容
            System.out.println("客户端" + getClientIp(ctx.channel()) + "->" + msg);
            //向所有客户端转发 当前数据
            Thread.sleep(1000);
            doAllReplay(msg);

            handlerData.handlerMsg(msg);
        }
    }
    /*
    * 当有新的客户端连接的时候，保存客户端消息
    * */
    public static class NettyChannelMap{
        public static Map<String,NettyClient> map = new ConcurrentHashMap<>();

        public static void add(String clientId,NettyClient client){
            map.put(clientId,client);
        }

        public static NettyClient get(String clientId){
            return map.get(clientId);
        }

        public static void remove(SocketChannel socketChannel){
            for (Map.Entry entry : map.entrySet()){
                if (((NettyClient) entry.getValue()).getChannel() == socketChannel){
                    map.remove(entry.getKey());
                }
            }
        }
    }

    /*
    * 封装客户端的消息
    * */
    @Data
    private class NettyClient {
        private SocketChannel channel; //客户端与服务端的链接
        private String clientIp; //Ip地址

       public NettyClient(SocketChannel channel,String clientIp){
           this.channel = channel;
           this.clientIp = clientIp;
       }
    }
}
